#include<iostream>
#include<map>
#include<unordered_map>
#include<cstring>
#include<cstdlib>
#include<cerrno>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<sys/types.h>          /* See NOTES */
#include<sys/socket.h>
#include<memory>
#include<functional>
#include<vector>
#include"ERR.hpp"
#include"Lock.hpp"
#include"Ringqueue.hpp"
#include"thread.hpp"
using namespace std;

namespace udp_server
{

    const static uint16_t _port=1111;
    using func_t =function<string(string)>;    //回调方法，封装
 

    class UdpServer
    {
    public:
    UdpServer(uint16_t port)
        // :_func(sv)
        :_port(port)
    {
        cout<<" [服务器端口] : "<<_port<<endl;
        pthread_mutex_init(&_lock,nullptr);
        
        t1 = new Thread(1,bind(&UdpServer::Recvform,this));
        t2 =new Thread(1,bind(&UdpServer::Sendto,this));



        
    }

    //服务器初始化 套接字(socket)->sockaddr_in初始化  -> 绑定(bind)
    void InitServer_Start()
    {
        //(1)创建套接字
        _sock=socket(AF_INET,SOCK_DGRAM,0);  //(ipv4协议,无连接不可靠,) 
        if(_sock<0)
        {
            cerr<<"创建 socker 失败: "<<strerror(errno)<<endl;
            exit(SOCKER_ERR);
        }
        cout<<"创建 socker 成功:"<<_sock<<endl;
        //（2）给指定服务器指明IP和port

        struct sockaddr_in local; //这个结构里主要有三部分信息: 地址类型, 端口号, IP地址.
        bzero(&local,sizeof(local)); //清理local

        //2.1初始化local
        local.sin_family=AF_INET;    
        local.sin_port=htons(_port);

        //2.2
        //inet_addr 把1-2 都做了
        //1.字符串风格转4字节
        //2.主机序列转网络序列
        //3.云服务器 或者一款服务器，不要指明某一个ip（可能会导致接受数据慢）云服务器不需要bind ip
        //4.物理机是允许的
        local.sin_addr.s_addr=INADDR_ANY;//bind本主机任意ip

        // local.sin_addr.s_addr=inet_addr(_ip.c_str());//sin_addr用来表示一个IPv4的IP地址


        //3.把填充字段绑定到网络(bind)
        if(bind(_sock,(struct sockaddr*)&local,sizeof(local))<0)
        {
            cerr<<"绑定失败: "<<strerror(errno)<<endl;
            exit(BIND_ERR); //返回错误码
        }
        cout<<"绑定 socker 成功:"<< _sock <<endl;

        t1->Runing();
        t2->Runing();


    }
    
    //通过map键对值查看用户是否存在
    void addUser(string name,struct sockaddr_in peer)
    {
        if(_ump.find(name)!=_ump.end())
        {
            return;
        }
        else 
        {
            _ump.insert(make_pair(name,peer));
        }


    }




    void Recvform()
    {
        char buf[256];
        while(true)
        {
            //收消息
            struct  sockaddr_in peer;
            socklen_t len =sizeof(peer);
           
            int n = recvfrom(_sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&peer,&len);
            if(n>0)
            {
                buf[n]='\0';
            }
            else 
            {
                continue;
            }
            cout<<"接收成功"<<endl;

            //客户端信息：端口号，ip
            string clientip =inet_ntoa(peer.sin_addr);//点分十进制ip
            uint16_t clientport=ntohs(peer.sin_port);//端口号
            
            //新建一个任务(ip，端口号)
            string name=clientip;
            name+="-";
            name+=to_string(clientport);
            addUser(name,peer);

            _rq.push(buf);



            //处理之后的信息
            // string sev=_func(buf);
            // cout<<clientip<<":"<<clientport<<":"<<"get message# "<<sev<<endl;



            // //发信息
            // sendto(_sock,sev.c_str(),sev.size(),0,(struct sockaddr*)&peer,len);

        }

        struct timeval *t;

    }

    void Sendto()
    {
        while(true)
        {
         string sending;

         _rq.pop(&sending); //消息pop到sending中

         vector<struct sockaddr_in>v; 
         
        {
            Lockguard Lockguard(&_lock);
            for(auto &e:_ump) //用vec去
            {
                v.push_back(e.second);
            }
            
        }
         for(auto e:v)
         {
             sendto(_sock,sending.c_str(),sending.size(),0,(struct sockaddr*)&e,sizeof(e));
             cout<<"发送成功"<<sending<<endl;
         }





        }



            


    }




    ~UdpServer()
    {   
        pthread_mutex_destroy(&_lock); //解锁
        t1->join();
        t2->join();

        delete t1;
        delete t2;
    }




    private:
        int _sock;  //描述符
        uint16_t _port;
        // string _ip;  不允许自己绑定
        // func_t _func; 刚刚是用自己的方法现在不需要了
        unordered_map<string,struct sockaddr_in>_ump;
        pthread_mutex_t   _lock;
        Ringqueue<string> _rq;
        Thread *t1;
        Thread *t2;


    };




};